using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;

namespace Sunny.UI;

public static class StructEx
{
	internal struct StructField
	{
		public string Field;

		public string Type;

		public int Offset;

		public int Size;

		public StructField(string field, string type, int offset, int size)
		{
			Field = field;
			Type = type;
			Offset = offset;
			Size = size;
		}
	}

	public const string StructLayoutString = "[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]";

	public const string StructMarshalAs = "[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]";

	public static T ToStruct<T>(this byte[] bytes) where T : struct
	{
		if (bytes == null)
		{
			throw new NullReferenceException();
		}
		int num;
		try
		{
			num = Marshal.SizeOf(typeof(T));
		}
		catch (Exception)
		{
			throw new NullReferenceException();
		}
		if (num > bytes.Length)
		{
			throw new NullReferenceException();
		}
		IntPtr intPtr = Marshal.AllocHGlobal(num);
		Marshal.Copy(bytes, 0, intPtr, num);
		object obj = Marshal.PtrToStructure(intPtr, typeof(T));
		Marshal.FreeHGlobal(intPtr);
		return (T)obj;
	}

	public static int Size<T>(T obj) where T : struct
	{
		return Marshal.SizeOf(typeof(T));
	}

	public static byte[] ToBytes<T>(this T obj) where T : struct
	{
		int num = Marshal.SizeOf(typeof(T));
		byte[] array = new byte[num];
		IntPtr intPtr = Marshal.AllocHGlobal(num);
		Marshal.StructureToPtr((object)obj, intPtr, fDeleteOld: false);
		Marshal.Copy(intPtr, array, 0, num);
		Marshal.FreeHGlobal(intPtr);
		return array;
	}

	public static bool Load<T>(this ref T obj, string dir, string fileName = "") where T : struct, IStructFile
	{
		if (!Path.IsPathRooted(dir))
		{
			Console.WriteLine("指定路径" + dir + "不包含根路径。");
			throw new ArgumentException(dir, "不包含根路径。");
		}
		string text = (fileName.IsValid() ? fileName : obj.FileName());
		if (File.Exists(dir.DealPath() + text))
		{
			try
			{
				byte[] bytes = File.ReadAllBytes(dir.DealPath() + text);
				obj = bytes.ToStruct<T>();
				return true;
			}
			catch (Exception ex)
			{
				Console.WriteLine(text + "加载失败，" + ex.Message);
			}
		}
		else
		{
			Console.WriteLine(text + "加载失败，数据文件不存在。");
		}
		return false;
	}

	public static bool Save<T>(this T obj, string dir, string fileName = "") where T : struct, IStructFile
	{
		if (!Path.IsPathRooted(dir))
		{
			throw new ArgumentException(dir, "不包含根路径。");
		}
		if (!Dir.CreateDir(dir))
		{
			throw new ArgumentNullException(dir, "路径不存在。");
		}
		string text = (fileName.IsValid() ? fileName : obj.FileName());
		if (text.IsNullOrEmpty())
		{
			throw new ArgumentNullException(text, "文件名不能为空。");
		}
		string text2 = dir.DealPath() + text;
		if (File.Exists(text2))
		{
			try
			{
				File.Delete(text2);
			}
			catch
			{
				Console.WriteLine(text2 + " 已存在，无法继续保存。");
				return false;
			}
		}
		try
		{
			byte[] array = obj.ToBytes();
			FileStream fileStream = new FileStream(text2, FileMode.Create);
			fileStream.Write(array, 0, array.Length);
			fileStream.Flush();
			fileStream.Close();
			return File.ReadAllBytes(text2).SequenceEqual(array);
		}
		catch (Exception ex)
		{
			Console.WriteLine(text2 + " 保存失败。" + ex.Message);
			return false;
		}
	}

	public static T Clone<T>(this T obj) where T : struct
	{
		return obj.ToBytes().ToStruct<T>();
	}

	public static string PrintStruct<T>() where T : struct
	{
		Type typeFromHandle = typeof(T);
		FieldInfo[] fields = typeFromHandle.GetFields(BindingFlags.Instance | BindingFlags.Public);
		int num = Marshal.SizeOf(typeof(T));
		List<StructField> list = new List<StructField>();
		int num2 = 0;
		string field = "";
		string type = "";
		int num3 = 0;
		FieldInfo[] array = fields;
		foreach (FieldInfo fieldInfo in array)
		{
			int num4 = Marshal.OffsetOf(typeFromHandle, fieldInfo.Name).ToInt32();
			num3 = num4 - num2;
			if (num3 > 0)
			{
				list.Add(new StructField(field, type, num2, num3));
			}
			num2 = num4;
			field = fieldInfo.Name;
			type = fieldInfo.FieldType.Name;
		}
		num3 = num - num2;
		if (num3 > 0)
		{
			list.Add(new StructField(field, type, num2, num3));
		}
		int num5 = 5;
		int num6 = 4;
		foreach (StructField item in list)
		{
			num5 = Math.Max(num5, item.Field.Length);
			num6 = Math.Max(num6, item.Type.Length);
		}
		num5 = (num5 / 4 + 2) * 4;
		num6 = (num6 / 4 + 2) * 4;
		int num7 = 12;
		int count = num5 + num6 + num7 + num7;
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.AppendLine("//-" + "-".Repeat(count));
		stringBuilder.AppendLine("// Struct Name: " + typeFromHandle.Name);
		stringBuilder.AppendLine("// " + $"Field Count: {fields.Length}");
		stringBuilder.AppendLine("// " + $"Total Size: {Marshal.SizeOf(typeFromHandle)} bytes");
		stringBuilder.AppendLine("//-" + "-".Repeat(count));
		if (fields.Length != 0)
		{
			stringBuilder.AppendLine("// " + "Field".PadRight(num5) + "Type".PadRight(num6) + "Offset".PadRight(num7) + "Size".PadRight(num7));
			stringBuilder.AppendLine("//-" + "-".Repeat(count));
			foreach (StructField item2 in list)
			{
				string[] obj = new string[5]
				{
					"// ",
					item2.Field.PadRight(num5),
					item2.Type.PadRight(num6),
					null,
					null
				};
				int i = item2.Offset;
				obj[3] = i.ToString().PadRight(num7);
				i = item2.Size;
				obj[4] = i.ToString().PadRight(num7);
				stringBuilder.AppendLine(string.Concat(obj));
			}
			stringBuilder.AppendLine("//-" + "-".Repeat(count));
		}
		list.Clear();
		return stringBuilder.ToString();
	}
}
